#include <iostream>
#include <unistd.h>
#include <assert.h>
#include <pthread.h>

using namespace std;

#define THREAD_NUM 15

class ThreadData
{
public:
    ThreadData(const std::string &name, pthread_mutex_t *pm)
        : t_name(name),
          pmtx(pm)
    {
    }

    std::string t_name;
    pthread_mutex_t *pmtx;
};

// pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; // 原生线程库提供的数据类型
int tickets = 10000; // 不加锁的情况下，并发访问会导致数据不一致，tickets应该是临界资源

void *getTickets(void *args)
{
    ThreadData *td = (ThreadData *)args;

    while (true)
    {
        pthread_mutex_lock(td->pmtx); // 加锁后变成临近区
        if (tickets > 0)
        {
            usleep(1000);
            printf("%s: %d\n", td->t_name.c_str(), tickets--);
            pthread_mutex_unlock(td->pmtx);
        }
        else
        {
            pthread_mutex_unlock(td->pmtx);
            break;
        }
    }
}

int main()
{
    pthread_mutex_t pt;
    int n = pthread_mutex_init(&pt, nullptr);
    assert(n == 0);

    pthread_t t[THREAD_NUM];
    for (int i = 0; i < THREAD_NUM; i++)
    {
        std::string name = "thread";
        name += to_string(i + 1);
        ThreadData *td = new ThreadData(name, &pt);
        pthread_create(&t[i], nullptr, getTickets, (void *)td);
    }

    for (int i = 0; i < THREAD_NUM; i++)
    {
        pthread_join(t[i], nullptr);
    }
    // pthread_create(&t1, nullptr, getTickets, nullptr);
    // pthread_create(&t2, nullptr, getTickets, nullptr);
    // pthread_create(&t3, nullptr, getTickets, nullptr);
    // pthread_join(t1, nullptr);
    // pthread_join(t2, nullptr);
    // pthread_join(t3, nullptr);

    pthread_mutex_destroy(&pt);
    return 0;
}